package gin

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"gitee.com/zacyuan/yuan/pkg/errors"
	"gitee.com/zacyuan/yuan/pkg/limiter"
	"gitee.com/zacyuan/yuan/pkg/log"
	"github.com/gin-gonic/gin"
)

type Hook func(Handler) Handler

func NewLog(appName string, showParams bool) func(next Handler) Handler {
	logger := log.With(log.String("app_name", appName))
	return func(next Handler) Handler {
		return func(ctx *Context) (any, error) {
			start := time.Now()
			l := logger.With(log.String(log.RequestID, ctx.GetRequestID()))
			ctx.Set(log.GinKey, l)

			rawData := ctx.GetRawData()
			rawQuery := ctx.Request.URL.RawQuery
			if !showParams {
				rawData = []byte("not show")
				rawQuery = ""
			}

			ret, err := next(ctx)
			buf, _ := json.Marshal(ret)

			l.Infof("[%v] [%s?%s] params[%s] resp[%s] err[%v]", time.Since(start), ctx.Request.URL.Path, rawQuery, string(rawData), string(buf), err)
			return ret, err
		}
	}
}

func NewIPLimiter(r limiter.Limit, b int) func(next Handler) Handler {
	return func(next Handler) Handler {
		return func(ctx *Context) (any, error) {
			ip := ctx.ClientIP()
			key := fmt.Sprintf("limit:%s", ip)
			limit := limiter.NewTokenLimiter(r, b, key)
			if !limit.Allow() {
				return &Return{
					Ret:       errors.ErrIPLimit.Code(),
					Msg:       errors.ErrIPLimit.Error(),
					RequestID: ctx.GetRequestID(),
				}, nil
			}
			return next(ctx)
		}
	}
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin") //请求头部
		if origin != "" {
			// 当Access-Control-Allow-Credentials为true时，将*替换为指定的域名
			c.Header("Access-Control-Allow-Origin", origin)
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-Extra-Header, Content-Type, Accept, Authorization")
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
			c.Header("Access-Control-Allow-Credentials", "true")
			c.Header("Access-Control-Max-Age", "86400") // 可选
			c.Set("content-type", "application/json")   // 可选
		}

		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}

		c.Next()
	}
}
